package com.service.admin.trading.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.service.admin.member.service.MemberService;
import com.service.admin.rabbitmq.binding.MatchSendHandler;
import com.service.admin.trading.controller.rep.SpotOrderDetailRep;
import com.service.admin.trading.controller.rep.SpotOrderPageRep;
import com.service.admin.trading.controller.rep.SpotTradeDetailRep;
import com.service.admin.trading.controller.req.CancelOrderReq;
import com.service.admin.trading.controller.req.SpotOrderPageReq;
import com.service.admin.trading.service.TradingSpotOrderService;
import com.service.admin.trading.service.TradingSpotTradesService;
import com.service.core.exception.CommonException;
import com.service.core.rest.response.CommonPageRep;
import com.service.dao.constants.ConfigConstants;
import com.service.dao.mapper.TradingSpotOrderMapper;
import com.service.dao.model.TradingSpotOrder;
import com.service.dao.po.TradingSpotOrderPO;
import com.service.dao.query.SpotOrderQueryParams;
import com.service.match.common.entity.SpotOrderVo;
import com.service.match.common.enums.TradingSpotEnum;
import com.service.match.common.utils.TradingSpotUtils;
import com.service.utility.modelmapper.ModelMapperUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.util.stream.Collectors;

@Slf4j
@Service
public class TradingSpotOrderServiceImpl extends ServiceImpl<TradingSpotOrderMapper, TradingSpotOrder> implements TradingSpotOrderService {

    @Autowired
    private TradingSpotTradesService tradingSpotTradesService;
    @Autowired
    private MatchSendHandler matchSendHandler;

    @Autowired
    private MemberService memberService;

    @Override
    public CommonPageRep<SpotOrderPageRep> pageOrder(SpotOrderPageReq pageReq) {
        Page<TradingSpotOrderPO> page = PageHelper.startPage(pageReq.getPageNo(), pageReq.getPageSize());
        SpotOrderQueryParams queryParams = ModelMapperUtil.map(pageReq, SpotOrderQueryParams.class);
        baseMapper.listOrderByQueryPrams(queryParams);
        return CommonPageRep.buildResultRep(page, page.getResult().stream()
                .map(item -> ModelMapperUtil.map(item, SpotOrderPageRep.class)).collect(Collectors.toList()));
    }

    @Override
    public SpotOrderDetailRep orderDetail(String orderNo) {

        TradingSpotOrder spotOrder = getOne(new QueryWrapper<TradingSpotOrder>().lambda()
                .eq(TradingSpotOrder::getTradeNo, orderNo)
                .last("limit 1"));

        SpotOrderDetailRep result = ModelMapperUtil.map(spotOrder, SpotOrderDetailRep.class);

        result.setTradeList(tradingSpotTradesService.listByOrderId(result.getId(), TradingSpotUtils.isBuy(result.getTradeType()))
                .stream().map(item -> {
                    SpotTradeDetailRep resultItem = ModelMapperUtil.map(item, SpotTradeDetailRep.class);
                    if (ObjectUtils.nullSafeEquals(spotOrder.getId(), item.getBuyOrderId())) {
                        resultItem.setSellMemberAccount(memberService.getById(item.getSellMemberId()).getUserAccount());
                        resultItem.setSellOrderNo(getById(item.getSellOrderId()).getTradeNo());
                    } else {
                        resultItem.setBuyMemberAccount(memberService.getById(item.getSellMemberId()).getUserAccount());
                        resultItem.setBuyOrderNo(getById(item.getSellOrderId()).getTradeNo());
                    }
                    return resultItem;
                }).collect(Collectors.toList()));

        return result;
    }

    @Override
    public void applyBatchCancelSpotOrder(CancelOrderReq cancelOrderReq) {

        cancelOrderReq.getOrderIdList().parallelStream().forEach(item -> {
            TradingSpotOrder spotOrder = getById(item);
            if (ObjectUtils.nullSafeEquals(spotOrder.getSpotStatus(), TradingSpotEnum.Status.COMPLETED.getCode())
                    || ObjectUtils.nullSafeEquals(spotOrder.getSpotStatus(), TradingSpotEnum.Status.CANCEL.getCode())) {
                log.info("订单:{}无法撤销,订单状态:{}", spotOrder.getId(), spotOrder.getSpotStatus());
                return;
            }
            //todo:发送至撮合引擎，从引擎测消交易
            matchSendHandler.sendCancelOrder(buildMsgVo(spotOrder, TradingSpotEnum.TradeType.of(spotOrder.getTradeType())
                    .orElseThrow(() -> new CommonException("不存在此交易", "trading_spot_exception_order_not_exist"))));
        });

    }

    @Override
    public void applyCancelSpotOrder(String tradeNo) {

        TradingSpotOrder spotOrder = getSpotOrderByNo(tradeNo);

        if (ObjectUtils.nullSafeEquals(spotOrder.getSpotStatus(), TradingSpotEnum.Status.COMPLETED.getCode())) {
            throw new CommonException("撤销失败，该交易已完成", "trading_spot_cancel_exception_order_has_completed");
        }
        if (ObjectUtils.nullSafeEquals(spotOrder.getSpotStatus(), TradingSpotEnum.Status.CANCEL.getCode())) {
            throw new CommonException("撤销失败，该交易已撤销", "trading_spot_cancel_exception_order_has_cancel");
        }
        //todo:发送至撮合引擎，从引擎测消交易
        matchSendHandler.sendCancelOrder(buildMsgVo(spotOrder, TradingSpotEnum.TradeType.of(spotOrder.getTradeType())
                .orElseThrow(() -> new CommonException("不存在此交易", "trading_spot_exception_order_not_exist"))));

    }

    public SpotOrderVo buildMsgVo(TradingSpotOrder spotOrder, TradingSpotEnum.TradeType tradeType) {
        return buildMsgVo(spotOrder, tradeType.getCode());
    }

    public SpotOrderVo buildMsgVo(TradingSpotOrder spotOrder, Integer tradeType) {
        SpotOrderVo msgVo = ModelMapperUtil.map(spotOrder, SpotOrderVo.class);
        msgVo.setFinishNumber(BigDecimal.ZERO);
        msgVo.setSpotState(spotOrder.getSpotStatus());
        msgVo.setSurplusFrozen(spotOrder.getSurplusFrozen());
        if (TradingSpotUtils.isBuy(tradeType)) {
            if (!TradingSpotUtils.isMarket(spotOrder.getPriceType())) {
                msgVo.setUnFinishNumber(spotOrder.getTradeNum());
            }
        } else {
            msgVo.setUnFinishNumber(spotOrder.getTradeNum());
        }
        return msgVo;
    }

    public TradingSpotOrder getSpotOrderByNo(String tradeNo) {
        TradingSpotOrder result = getOne(new QueryWrapper<TradingSpotOrder>().lambda()
                .eq(TradingSpotOrder::getTradeNo, tradeNo).last("limit 1"));
        if (ObjectUtils.isEmpty(result)) {
            throw new CommonException("不存在此交易", "trading_spot_exception_order_not_exist");
        }
        return result;
    }
}
